﻿namespace VisualSVN.Core.Licensing
{
    using System;
    using System.IO;
    using System.Text;
    using VisualSVN.Core;

    public class NewLicenseSerializer
    {
        public License Deserialize(string key, IDecoder decoder)
        {
            byte[] data = Base32Decoder.Decode(key);
            using (MemoryStream stream = new MemoryStream(decoder.Decode(data)))
            {
                return ReadLicenseFromStream(stream);
            }
        }

        private static string ReadBytePrefixedString(BinaryReader reader)
        {
            int count = reader.ReadByte();
            char[] chArray = reader.ReadChars(count);
            if (chArray.Length != count)
            {
                throw new EndOfStreamException();
            }
            return new string(chArray);
        }

        private static DateTime ReadDateTime(BinaryReader reader)
        {
            return new DateTime(reader.ReadInt64());
        }

        private static License ReadLicenseFromStream(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream, Encoding.UTF8);
            License license = new License();
            license.Version = reader.ReadByte();
            license.Type = (LicenseType) reader.ReadByte();
            license.Binding = (LicenseBinding) reader.ReadByte();
            license.Capacity = reader.ReadInt32();
            license.LicensedTo = ReadBytePrefixedString(reader);
            license.StartTime = ReadDateTime(reader);
            license.EndTime = ReadDateTime(reader);
            license.LicenseId = new Guid(ReadBytePrefixedString(reader));
            license.PurchaseId = ReadBytePrefixedString(reader);
            license.PurchaseDate = ReadDateTime(reader);
            return license;
        }

        public string Serialize(License license, IEncoder encoder)
        {
            byte[] buffer;
            using (MemoryStream stream = new MemoryStream())
            {
                WriteLicenseToStream(license, stream);
                buffer = stream.ToArray();
            }
            return Base32Encoder.Encode(encoder.Encode(buffer));
        }

        private static void WriteBytePrefixedString(BinaryWriter writer, string str)
        {
            if (str.Length > 0xff)
            {
                throw new ArgumentOutOfRangeException("str", str, "String is too long.");
            }
            writer.Write((byte) str.Length);
            writer.Write(str.ToCharArray());
        }

        private static void WriteDateTime(BinaryWriter writer, DateTime date)
        {
            writer.Write(date.Ticks);
        }

        private static void WriteLicenseToStream(License license, Stream stream)
        {
            BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8);
            writer.Write(license.Version);
            writer.Write((byte) license.Type);
            writer.Write((byte) license.Binding);
            writer.Write(license.Capacity);
            WriteBytePrefixedString(writer, license.LicensedTo);
            WriteDateTime(writer, license.StartTime);
            WriteDateTime(writer, license.EndTime);
            WriteBytePrefixedString(writer, license.LicenseId.ToString());
            WriteBytePrefixedString(writer, license.PurchaseId);
            WriteDateTime(writer, license.PurchaseDate);
        }
    }
}

